package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author bo.li
 * @Date 2023/2/2 10:59
 * @Version 1.0
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    private WmNewsMapper newsMapper;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private WmChannelMapper channelMapper;
    @Autowired
    private WmUserMapper userMapper;

    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmSensitiveMapper sensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    @Async
    @Override
    public void autoScan(WmNews wmNews) {
        if(wmNews.getStatus() != WmNews.Status.SUBMIT.getCode()){
            log.info("文章状态不是待审核，不做审核");
            return;
        }
        //从正文或者封面图片中提取文本和图片
        Map<String,Object> textAndImage = getTextAndImage(wmNews);

        //自定义敏感词审核
        boolean flag = handleSensitive((String)textAndImage.get("text"),wmNews);
        if(!flag){
            log.error("文本审核未通过,包含敏感词，不走后续流程");
            return;
        }

        //文本审核
        flag = handleTextScan((String)textAndImage.get("text"),wmNews);
        if(!flag){
            log.error("文本审核未通过，不走后续流程");
            return;
        }
        //图片审核
        flag = handleImageScan((List<String>)textAndImage.get("images"),wmNews);
        if(!flag){
            log.error("图片审核未通过，不走后续流程");
            return;
        }
        //保存APP端
        ResponseResult result = saveToApp(wmNews);
        if(200 != result.getCode()){
            log.error("同步到APP端文章失败，原因：{}",result.getErrorMessage());
            return;
        }

        //回填文章id
        Long articleId = (Long)result.getData();
        wmNews.setArticleId(articleId);
        updateNews(wmNews,WmNews.Status.PUBLISHED.getCode(),"审核成功");
    }

    /**
     *
     * 自定义敏感词审核
     * @param text
     * @param wmNews
     */
    private boolean handleSensitive(String text, WmNews wmNews) {
        boolean flag = true;
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        if(CollectionUtils.isEmpty(wmSensitives)){
            return flag;
        }
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        SensitiveWordUtil.initMap(sensitiveList);

        Map<String, Integer> reslutMap = SensitiveWordUtil.matchWords(text);
        log.info("敏感词审核结果：{}",reslutMap);
        if(reslutMap.size() > 0){
            updateNews(wmNews,WmNews.Status.FAIL.getCode(), "文章中含有敏感词：" + reslutMap);
            flag = false;
        }
        return flag;
    }

    /**
     * 调用APP保存文章
     *
     * @param wmNews
     */
    private ResponseResult saveToApp(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);

        dto.setLayout(wmNews.getType());
        dto.setAuthorId(wmNews.getUserId());

        //渠道处理
        WmChannel channel = channelMapper.selectById(wmNews.getChannelId());
        dto.setChannelName(channel == null ? null : channel.getName());

        //用户昵称
        WmUser user = userMapper.selectById(wmNews.getUserId());
        dto.setAuthorName(user.getNickname());

        if(wmNews.getArticleId() != null){
            dto.setId(wmNews.getArticleId());
        }

        return articleClient.saveArticle(dto);
    }

    /**
     * 审核图片
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            if(CollectionUtils.isEmpty(images)){
                return flag;
            }
            List<byte[]> imageList = new ArrayList<>();
            for(String path : images) {
                byte[] imageByte = fileStorageService.downLoadFile(path);
                //敏感词处理
                String result = tess4jClient.doOCR(ImageIO.read(new ByteArrayInputStream(imageByte)));
                flag = handleSensitive(result, wmNews);
                if(!flag){
                    log.info("图片中含敏感字符，不做后续处理");
                    return flag;
                }

                imageList.add(imageByte);
            }

            Map map = imageScan.imageScan(imageList);
            log.info("图片审核结果：{}",map);
            if(map == null){
                return false;
            }
            String suggestion = (String)map.get("suggestion");
            String lable = (String)map.get("label");
            if("block".equals(suggestion)){
                flag = false;
                updateNews(wmNews,WmNews.Status.FAIL.getCode(),"图片中存在违规内容:" + lable);
            }
            if("review".equals(suggestion)){
                flag = false;
                updateNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"图片中存在不确定内容");
            }
        } catch (Exception e) {
            log.error("图片审核异常",e);
            flag = false;
        }

        return flag;
    }

    /**
     * 文本审核
     *
     * @param text
     */
    private boolean handleTextScan(String text,WmNews wmNews) {
        boolean flag = true;
        if(StringUtils.isEmpty(text)){
            return true;
        }
        try {
            Map map = greenTextScan.greeTextScan(text);
            log.info("文本审核结果：{}",map);
            if(map == null){
                return false;
            }
            String suggestion = (String)map.get("suggestion");
            String lable = (String)map.get("label");
            if("block".equals(suggestion)){
                flag = false;
                updateNews(wmNews,WmNews.Status.FAIL.getCode(),"文本中存在违规内容:" + lable);
            }
            if("review".equals(suggestion)){
                flag = false;
                updateNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"文本中存在不确定内容");
            }

        } catch (Exception e) {
            log.error("阿里云文本扫描异常",e);
        }

        return flag;
    }

    /**
     * 更新文章表
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateNews(WmNews wmNews, Short status, String reason){
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        newsMapper.updateById(wmNews);
    }

    /**
     * 提取文本及图片
     *
     * @param wmNews
     */
    private Map getTextAndImage(WmNews wmNews) {
        Map<String,Object> result = new HashMap<>();
        //正文
        StringBuilder stringBuilder = new StringBuilder();
        //图片
        List<String> images = new ArrayList<>();

        List<Map> contentList = JSON.parseArray(wmNews.getContent(),Map.class);
        for(Map map : contentList){
            String type = map.get("type").toString();
            String value = map.get("value").toString();
            if("text".equals(type)){
                stringBuilder.append(value);
            }
            if("image".equals(type)){
                images.add(value);
            }
        }

        if(!StringUtils.isEmpty(wmNews.getImages())){
            images.addAll(StringUtils.commaDelimitedListToSet(wmNews.getImages()));
        }

        //文本加标题
        stringBuilder.append("-").append(wmNews.getTitle());

        //去重
        images.stream().distinct().collect(Collectors.toList());

        result.put("text",stringBuilder.toString());
        result.put("images",images);

        return result;
    }
}